package com.inspur.edp.das.commonmodel.json.object;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.BaseList;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationKeyCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.entity.GspCommonDataType;
import com.inspur.edp.cef.designtime.api.entity.MdRefInfo;
import com.inspur.edp.cef.designtime.api.json.element.GspAssoKeyDeserializer;
import com.inspur.edp.cef.designtime.api.json.object.GspCommonDataTypeDeserializer;
import com.inspur.edp.das.commonmodel.collection.GspElementCollection;
import com.inspur.edp.das.commonmodel.collection.GspObjectCollection;
import com.inspur.edp.das.commonmodel.collection.GspUniqueConstraintCollection;
import com.inspur.edp.das.commonmodel.entity.GspCommonObject;
import com.inspur.edp.das.commonmodel.entity.object.ConstraintType;
import com.inspur.edp.das.commonmodel.entity.object.GspColumnGenerate;
import com.inspur.edp.das.commonmodel.entity.object.GspCommonObjectType;
import com.inspur.edp.das.commonmodel.entity.object.GspUniqueConstraint;
import com.inspur.edp.das.commonmodel.exception.CommonModelErrorCodeEnum;
import com.inspur.edp.das.commonmodel.exception.CommonModelException;
import com.inspur.edp.das.commonmodel.json.CommonModelNames;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;
import com.inspur.edp.cef.designtime.api.json.element.CefFieldDeserializer;
import com.inspur.edp.das.commonmodel.json.element.CmElementDeserializer;

import java.io.IOException;
import java.util.ArrayList;

import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

/**
 * The Json Deserializer Of Common Model Object
 *
 * @ClassName: CmObjectDeserializer
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public abstract class CmObjectDeserializer extends GspCommonDataTypeDeserializer {

	protected abstract void beforeCMObjectDeserializer(GspCommonObject field);
    @Override
	protected final void beforeCefObjectDeserializer(GspCommonDataType commonDataType){
		GspCommonObject object = (GspCommonObject) commonDataType;
		beforeCMObjectDeserializer(object);
		object.setRepositoryComps(new ArrayList<>());
		object.setRefObjectName("");
		object.setObjectType(GspCommonObjectType.MainObject);
//		object.setParentObject(new GspCommonObject());
		GspObjectCollection collection = createChildObjectCollection();
        object.setContainChildObjects(collection);
        object.setReadOnly(false);
        object.setIsVirtual(false);
		object.setKeys(new GspAssociationKeyCollection());

    }

	@Override
	protected final boolean readExtendDataTypeProperty(GspCommonDataType commonDataType, String propName, JsonParser jsonParser) {
		boolean result = true;
		GspCommonObject object = (GspCommonObject) commonDataType;
		switch (propName) {
			case CommonModelNames.RepositoryComps:
				ArrayList<MdRefInfo> infos = new ArrayList<>();
				try {
//					SerializerUtils.readStartArray(jsonParser);
					ObjectMapper mapper = new ObjectMapper();
					JavaType type = mapper.getTypeFactory().
							constructCollectionType(ArrayList.class, MdRefInfo.class);
					infos = mapper.readValue(jsonParser, type);
					jsonParser.nextToken();
				} catch (IOException e) {
					throw CommonModelException.createException(
							CommonModelErrorCodeEnum.GSP_BEMODEL_JSON_0002, e, "CmObjectDeserializer", propName);
				}
				object.setRepositoryComps(infos);
				break;
			case CommonModelNames.ObjectType:
				object.setObjectType(SerializerUtils.readPropertyValue_Enum(jsonParser, GspCommonObjectType.class, GspCommonObjectType.values()));
				break;
			case CommonModelNames.RefObjectName:
				object.setRefObjectName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.LogicDelete:
				SerializerUtils.readPropertyValue_boolean(jsonParser);
				break;
			case CommonModelNames.ColumnGenerateID:
				object.setColumnGenerateID(readColumnGenerateId(jsonParser));
				break;
			case CommonModelNames.ContainChildObjects:
				readContainChildObjects(jsonParser, object);
				break;
			case CommonModelNames.ContainConstraints:
				readContainConstraints(jsonParser, object);
				break;
			case CommonModelNames.OrderbyCondition:
				object.setOrderbyCondition(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.FilterCondition:
				object.setFilterCondition(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.ModifiedDateElementID:
			case CommonModelNames.CreatorElementID:
			case CommonModelNames.ModifierElementID:
			case CommonModelNames.CreatedDateElementID:
			case CommonModelNames.StateElementID:
				SerializerUtils.readPropertyValue_String(jsonParser);
				break;
			case CommonModelNames.RecordDelData:
				SerializerUtils.readPropertyValue_boolean(jsonParser);
				break;
			case CommonModelNames.IsReadOnly:
				object.setIsReadOnly(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CommonModelNames.IsVirtual:
				object.setIsVirtual(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CommonModelNames.HirarchyInfo:
				readHirarchyInfo(jsonParser);
				break;
			case CommonModelNames.Keys:
				readKeys(jsonParser, object);
				break;
			case "ParentObjectID":
				SerializerUtils.readPropertyValue_String(jsonParser);
				break;
			case CommonModelNames.BelongModelID:
				object.setBelongModelID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;

			default:
				result = ReadExtendObjectProperty(object, propName, jsonParser);
				break;
		}
		return result;
	}

	protected void readKeys(JsonParser jsonParser, GspCommonObject object) {
		GspAssociationKeyCollection collection = new GspAssociationKeyCollection();
		GspAssoKeyDeserializer deserializer = new GspAssoKeyDeserializer();
		SerializerUtils.readArray(jsonParser, deserializer, collection);
		object.setKeys(collection);
	}

	//hirachyInfo无用，已删除
	private void readHirarchyInfo(JsonParser jsonParser) {
		JsonDeserializer<GspUniqueConstraint> deserializer = new JsonDeserializer<GspUniqueConstraint>() {
			@Override
			public GspUniqueConstraint deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
				GspUniqueConstraint hirarchyInfo = new GspUniqueConstraint();

				SerializerUtils.readStartObject(jsonParser);
				while (jsonParser.getCurrentToken() == FIELD_NAME) {
					String propName = SerializerUtils.readPropertyName(jsonParser);
					switch (propName) {
						case CommonModelNames.ISDETAILELEMENT:
							SerializerUtils.readPropertyValue_String(jsonParser);
							break;
						case CommonModelNames.LayerElement:
							SerializerUtils.readPropertyValue_String(jsonParser);
							break;
						case CommonModelNames.ParentElement:
							SerializerUtils.readPropertyValue_String(jsonParser);
							break;
						case CommonModelNames.ParentRefElement:
							SerializerUtils.readPropertyValue_String(jsonParser);
							break;
						case CommonModelNames.PathElement:
							SerializerUtils.readPropertyValue_String(jsonParser);
							break;
						case CommonModelNames.PathGenerateType:
							SerializerUtils.readPropertyValue_Integer(jsonParser);
							break;
						case CommonModelNames.PathLength:
							SerializerUtils.readPropertyValue_Integer(jsonParser);
							break;
					}
				}
				SerializerUtils.readEndObject(jsonParser);
				return null;
			}
		};
		try {
			deserializer.deserialize(jsonParser, null);
		} catch (IOException e) {
			throw CommonModelException.createException(CommonModelErrorCodeEnum.GSP_BEMODEL_JSON_0001,e, "GspUniqueConstraint");
		}
	}

	private void readContainConstraints(JsonParser jsonParser, GspCommonObject object) {
		GspUniqueConstraintCollection collection = new GspUniqueConstraintCollection();
		JsonDeserializer<GspUniqueConstraint> deserializer = new JsonDeserializer<GspUniqueConstraint>() {
			@Override
			public GspUniqueConstraint deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
				GspUniqueConstraint value = new GspUniqueConstraint();

				SerializerUtils.readStartObject(jsonParser);
				while (jsonParser.getCurrentToken() == FIELD_NAME) {
					String propName = SerializerUtils.readPropertyName(jsonParser);
					switch (propName) {
						case CommonModelNames.ID:
							value.setId(SerializerUtils.readPropertyValue_String(jsonParser));
							break;
						case CommonModelNames.Code:
							value.setCode(SerializerUtils.readPropertyValue_String(jsonParser));
							break;
						case CommonModelNames.Name:
							value.setName(SerializerUtils.readPropertyValue_String(jsonParser));
							break;
						case CommonModelNames.Type:
							value.setType(SerializerUtils.readPropertyValue_Enum(jsonParser, ConstraintType.class, ConstraintType.values()));
							break;
						case CommonModelNames.ConstraintMessage:
							value.setConstraintMessage(SerializerUtils.readPropertyValue_String(jsonParser));
							break;
						case CommonModelNames.ElementList:
							GspElementCollection collection = new GspElementCollection(getGspCommonDataType());
							CefFieldDeserializer deserializer = createFieldDeserializer();
							SerializerUtils.readArray(jsonParser, deserializer, collection);
							BaseList<String> list = new BaseList<String>();
							for (IGspCommonField field : collection) {
								list.add(field.getID());
							}
							value.setElementList(list);
							break;
						case CefNames.I18nResourceInfoPrefix:
							value.setI18nResourceInfoPrefix(SerializerUtils.readPropertyValue_String(jsonParser));
							break;

					}
				}
				SerializerUtils.readEndObject(jsonParser);
				return value;
			}
		};
		SerializerUtils.readArray(jsonParser, deserializer, collection);
		object.setContainConstraints(collection);
	}

	private void readContainChildObjects(JsonParser parser, GspCommonObject object) {
		GspObjectCollection collection = createChildObjectCollection();
		CmObjectDeserializer deserializer = createCmObjectDeserializer();
		deserializer.setFlag(getFlag());
		if (SerializerUtils.readNullObject(parser)) {
			return;
		}
		SerializerUtils.readStartArray(parser);
		JsonToken tokentype = parser.getCurrentToken();
		if (tokentype != END_ARRAY) {
			while (parser.getCurrentToken() == tokentype) {
				GspCommonObject item = (GspCommonObject) deserializer.deserializeCommonDataType(parser);
				collection.add(item);
			}
		}
		SerializerUtils.readEndArray(parser);
		object.setContainChildObjects(collection);
	}

	protected abstract CmObjectDeserializer createCmObjectDeserializer();

	private GspColumnGenerate readColumnGenerateId(JsonParser jsonParser) {
		GspColumnGenerate columnGenerate = new GspColumnGenerate();
		if (SerializerUtils.readNullObject(jsonParser)) {
			return columnGenerate;
		}
		SerializerUtils.readStartObject(jsonParser);
		while (jsonParser.getCurrentToken() == FIELD_NAME) {
			String propName = SerializerUtils.readPropertyName(jsonParser);
			readColumnGenerateIdPropValue(jsonParser, propName, columnGenerate);
		}
		SerializerUtils.readEndObject(jsonParser);
		return columnGenerate;
	}

	private void readColumnGenerateIdPropValue(JsonParser jsonParser, String propName, GspColumnGenerate columnGenerate) {
		switch (propName) {
			case CommonModelNames.ElementID:
				columnGenerate.setElementID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.GernerateType:
			case CommonModelNames.GenerateType:
				columnGenerate.setGenerateType(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.ColumnParameters:
				columnGenerate.setCloumnParameter(SerializerUtils.readStringArray(jsonParser));
				break;
			default:
				throw CommonModelException.createException(CommonModelErrorCodeEnum.GSP_BEMODEL_COMMON_MODEL_0001,
						"GspCommonDataTypeDeserializer.readColumnGenerateIdPropValue", propName);
		}
	}

	protected boolean ReadExtendObjectProperty(GspCommonObject object, String propName, JsonParser jsonParser) {
		return false;
	}

	@Override
	protected final GspCommonDataType createCommonDataType() {
		return CreateCommonObject();
	}

	@Override
	protected final CefFieldDeserializer createFieldDeserializer() {
		return CreateElementDeserializer();
	}

	@Override
	protected final GspFieldCollection createFieldCollection() {
		return createCommonElementCollection();
	}

	protected GspElementCollection createCommonElementCollection() {
		return new GspElementCollection(getGspCommonDataType());
	}

	protected GspObjectCollection createChildObjectCollection() {
		return new GspObjectCollection(getGspCommonDataType());
	}

	@Override
	protected final GspCommonObject getGspCommonDataType() {
		return (GspCommonObject) super.getGspCommonDataType();
	}

	protected abstract GspCommonObject CreateCommonObject();

	protected abstract CmElementDeserializer CreateElementDeserializer();
}
